package drds.plus.repository.mysql.handler;

import drds.plus.executor.ExecuteContext;
import drds.plus.executor.command_handler.CommandHandler;
import drds.plus.executor.command_handler.query.QueryHandler;
import drds.plus.executor.cursor.cursor.ISortingCursor;
import drds.plus.executor.cursor.cursor.impl.SortingCursor;
import drds.plus.executor.cursor.cursor_metadata.CursorMetaData;
import drds.plus.executor.repository.IDatasourceManagerGetter;
import drds.plus.executor.utils.Utils;
import drds.plus.repository.mysql.spi.CursorImpl;
import drds.plus.repository.mysql.spi.DatasourceManagerGetterImpl;
import drds.plus.repository.mysql.spi.JdbcHandler;
import drds.plus.repository.mysql.spi.RepositoryImpl;
import drds.plus.repository.mysql.utils.MysqlRepoUtils;
import drds.plus.sql_process.abstract_syntax_tree.configuration.IndexMapping;
import drds.plus.sql_process.abstract_syntax_tree.execute_plan.ExecutePlan;
import drds.plus.sql_process.abstract_syntax_tree.execute_plan.query.Join;
import drds.plus.sql_process.abstract_syntax_tree.execute_plan.query.Query;
import drds.plus.sql_process.abstract_syntax_tree.execute_plan.query.QueryWithIndex;
import drds.plus.sql_process.abstract_syntax_tree.expression.order_by.OrderBy;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;

import java.util.List;

/**
 * mysql 查询逻辑
 */
@Slf4j
public class QueryMyHandler extends QueryHandler implements CommandHandler {
    public Logger log() {
        return log;
    }

    protected IDatasourceManagerGetter dataNodeDataSourceGetter;

    public QueryMyHandler() {
        super();
        dataNodeDataSourceGetter = new DatasourceManagerGetterImpl();
    }


    public ISortingCursor handle(ExecuteContext executeContext, ExecutePlan executePlan) throws RuntimeException {
        if (!canComposeOneSql(executePlan)) {
            return super.handle(executeContext, executePlan);
        }

        IndexMapping indexMapping = null;
        JdbcHandler jdbcHandler = ((RepositoryImpl) executeContext.getRepository()).getJdbcHandler(executeContext, executePlan, dataNodeDataSourceGetter);
        CursorMetaData cursorMetaData = Utils.convertIndexMetaDataToCursorMetaData((Query) executePlan);
        CursorImpl cursorImpl = new CursorImpl(executePlan, executePlan.isStreaming(), cursorMetaData, jdbcHandler);

        if (executePlan.getSql() != null) {
            return cursorImpl.getResultSet();
        }

        List<OrderBy> orderByList = null;
        if (executePlan instanceof Join) {
            orderByList = ((Join) executePlan).getOrderByList();
        } else {
            orderByList = MysqlRepoUtils.buildOrderBy(executePlan, indexMapping);
        }

        orderByList = Utils.copyOrderByList(orderByList);

        for (OrderBy orderBy : orderByList) {
            if (((Query) executePlan).getAlias() != null) {
                orderBy.getItem().setTableName(((Query) executePlan).getAlias());
            }
            if (orderBy.getItem().getAlias() != null)
                orderBy.getItem().setColumnName(orderBy.getItem().getAlias());
        }

        if (!executePlan.isLazyLoad()) {
            /**
             * 非延迟加载进行真正的查询
             */
            cursorImpl.init();
        }
        ISortingCursor cursor = new SortingCursor(cursorImpl, cursorMetaData, orderByList);
        if (((Query) executePlan).getSubQueryFilter() != null) {
            cursor = executeContext.getRepository().getCursorFactory().valueFilterCursor(executeContext, cursor, ((Query) executePlan).getSubQueryFilter());
        }
        return cursor;
    }

    protected boolean canComposeOneSql(ExecutePlan executePlan) {
        if (executePlan instanceof QueryWithIndex) {
            QueryWithIndex queryWithIndex = (QueryWithIndex) executePlan;
            Query query = queryWithIndex.getSubQuery();
            if (query == null) {
                return true;
            }
            String queryDataNodeId = queryWithIndex.getDataNodeId();
            String queryTreeDataNodeId = query.getDataNodeId();
            if (queryDataNodeId.equals(queryTreeDataNodeId)) {
                return isConsistent(query, queryDataNodeId);
            } else {
                return false;
            }
        } else {
            return true;
        }
    }

    private boolean isConsistent(Query query, String dataNodeId) {
        if (query instanceof QueryWithIndex) {
            QueryWithIndex queryWithIndex = (QueryWithIndex) query;
            Query subQuery = queryWithIndex.getSubQuery();
            if (subQuery == null) {
                return true;
            } else {
                String queryTreeDataNodeId = query.getDataNodeId();
                if (dataNodeId.equals(queryTreeDataNodeId)) {
                    return isConsistent(query, dataNodeId);
                } else {
                    return false;
                }
            }
        } else {
            return false;
        }
    }

}
